package ua.org.extjsbuilder.projects;

import java.io.ByteArrayInputStream;
import java.io.Externalizable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.util.LinkedList;
import java.util.List;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;

public class ExtjsProjectConfiguration implements Externalizable {
	public static final String CONFIG_FILE = ".extjsProject";
	private IProject project;
	private IPath binDir;
	private IPath srcDir;
	private IPath binFile;
	
	private ExtjsProjectConfiguration(IProject project){
		this.project = project;
	}
	
	private void init(IProject project){
		binDir = new Path("bin");//TODO: make this property configurable in project wizard
		srcDir = new Path("src");//TODO: make this property configurable in project wizard
		binFile = new Path("result.js");//TODO: make property configurable
	}

	public String getName() {
		return project.getName();
	}

	public IPath getBinaryDir() {
		return binDir;
	}

	public IPath getSourceDir() {
		return srcDir;
	}

	public static ExtjsProjectConfiguration getInstance(IProject project) throws CoreException {
		ExtjsProjectConfiguration result = new ExtjsProjectConfiguration(project);
		IFile config = project.getFile(CONFIG_FILE);
		if(config.exists()){
			readConfig(result,config);
		}
		else {
			config.create(new ByteArrayInputStream(new byte[0]), 
					IFile.FORCE|IFile.TEAM_PRIVATE, null);
			result.init(project);
			saveConfig(result,config);
		}
		return result;
	}

	private static void saveConfig(ExtjsProjectConfiguration result,
			IFile config) {
		try {
			ObjectOutputStream out = new ObjectOutputStream(
					new FileOutputStream(config.getLocation().toFile()));
			result.writeExternal(out);
			out.flush();
			out.close();
		}
		catch(IOException ex){
			throw new RuntimeException(ex);
		}
	}

	private static void readConfig(ExtjsProjectConfiguration result,
			IFile config) {
		try {
			ObjectInputStream in = new ObjectInputStream(
					new FileInputStream(config.getLocation().toFile()));
			result.readExternal(in);
			in.close();
		}
		catch(IOException ex){
			throw new RuntimeException(ex);
		} 
		catch (ClassNotFoundException ex) {
			throw new RuntimeException(ex);
		}
	}

	public List<File> getConfiguredLinkOrder() {
		//TODO: Make order configurable (now it is random)
		return getAllJSFiles(project.getFolder(getBinaryDir())
				.getLocation().toFile(),new LinkedList<File>());
	}

	private List<File> getAllJSFiles(File file, LinkedList<File> result) {
		for(String name : file.list()){
			if(name==null||name.equals(".")||
					name.equals("..")){
				continue;
			}
			File child = new File(file,name);
			if(child.isDirectory()){
				getAllJSFiles(child,result);
			}
			else if(child.isFile()&&child.getName().endsWith(".js")){
				result.add(child);
			}
		}
		return result;
	}

	public IPath getBinaryFile() {
		return binFile;
	}

	public void readExternal(ObjectInput in) throws IOException,
			ClassNotFoundException {
		binDir = new Path(in.readUTF());
		srcDir = new Path(in.readUTF());
		binFile = new Path(in.readUTF());
	}

	public void writeExternal(ObjectOutput out) throws IOException {
		out.writeUTF(binDir==null?"":binDir.toPortableString());
		out.writeUTF(srcDir==null?"":srcDir.toPortableString());
		out.writeUTF(binFile==null?"":binFile.toPortableString());
	}
}
